//
// Created by cube on 2020/8/26.
//

#ifndef COMPILERDOMEA1_ALGORIHMTEMPLATE_H
#define COMPILERDOMEA1_ALGORIHMTEMPLATE_H

#include <mutex>
#include <atomic>
#include <memory>
#include <set>
#include <map>
#include <list>

namespace Lib{

/**********************************************************
#define BASE_OBJ\
    static int type(){ static int type = getNewType(); return type;}\
    int getType() override {return type();}

class Base_obj{
public:
    static int type(){
        static int type = getNewType();
        return type;
    }

    virtual int getType(){
        return type();
    }

protected:
    static int getNewType(){
        static int base = 0;
        return base++;
    }
};
 **********************************************************/

#define LIB_TYPE_BASE_CLASS(T)\
    static T type(){static T type = getNewType();return type;}\
    virtual T getType() const {return type();}\
    protected:\
    static T getNewType(){static T base = 0;return base++;}

#define LIB_TYPE_SUB_CLASS(T,B)\
    static T type(){ static T type = B::getNewType(); return type;}\
    T getType() const override {return type();}


    //==================================================================

    struct PublicSingle{
        template <typename T,typename ...Args>
        static T& singleCase(Args ...args){
            static T __single_case = T(std::forward<Args>(args)...);
            return __single_case;
        }
    };

    template <typename T,typename ...Args>
    class SingleCase{
    public:
        static T& singleCase(Args ...args){
            return PublicSingle::singleCase<T,Args...>(std::forward<Args>(args)...);
        }
    };

    template <typename T,typename ...Args>
    T& thread_data(Args ...args){
        thread_local T t = T(std::forward<Args>(args)...);
        return t;
    }

    //=====================================================================

    template <typename _D>
    class Implicit_Sharing{
    public:
        Implicit_Sharing():__pr_data(create_DataBase()){}
        Implicit_Sharing(std::shared_ptr<_D>& data):__pr_data(data){}

    public:
        const _D& operator()() const {return *(_D*)&data();}
        _D& operator()() {return *(_D*)&data();}
        std::shared_ptr<_D>& baseData(){return __pr_data;}

    protected:
        _D* create_DataBase(){return new _D();}
        _D* create_DataBase(_D* base){
            _D* data = new _D();
            (*data) = (*(_D*)base);
            return data;
        }

        const _D& data() const {
//            std::cout<<"get"<<std::endl;
            return *__pr_data.get();
        }

        _D& data(){
//            std::cout<<"set"<<std::endl;
            if(__pr_data.use_count() > 1){
                __pr_data.reset(create_DataBase(__pr_data.get()));
            } else if(!__pr_data)__pr_data.reset(create_DataBase());
            return *__pr_data.get();
        }

    private:
        std::shared_ptr<_D> __pr_data;
    };

}


//------------------------------------------------------------------------

//struct Data{
//    ~Data(){
//        std::cout<<"d"<<std::endl;
//    }
//    int a;
//};
//
//class Te : public Implicit_Sharing<Te,Data>{
//public:
//    using Implicit_Sharing::Implicit_Sharing;
//    int getA() const {
//        return data().a;
//    }
//
//    void setA(int a){
//        data().a = a;
//    }
//
//    Data* getData(){
//        return __pr_data.get();
//    }
//};
//
//Te t;
//Te t1 = t;
//Te t2;
//
//std::cout<<t.getData()<<std::endl;
//std::cout<<t1.getData()<<std::endl;
//std::cout<<t2.getData()<<std::endl;
//
//t.setA(3);
//
//std::cout<<t.getData()<<std::endl;
//std::cout<<t1.getData()<<std::endl;
//std::cout<<t2.getData()<<std::endl;
//
//t1.setA(2);
//t2 = t1;
////    const Te& t1 = t;
//
//std::cout<<t.getData()<<std::endl;
//std::cout<<t1.getData()<<std::endl;
//std::cout<<t2.getData()<<std::endl;
//
//Te* tp = new Te(&t);
//std::cout<<t.getData()<<std::endl;
//std::cout<<t1.getData()<<std::endl;
//std::cout<<t2.getData()<<std::endl;
//std::cout<<tp->getData()<<std::endl;
//
//tp->setA(3);
//std::cout<<t.getData()<<std::endl;
//std::cout<<t1.getData()<<std::endl;
//std::cout<<t2.getData()<<std::endl;
//std::cout<<tp->getData()<<std::endl;

#endif //COMPILERDOMEA1_ALGORIHMTEMPLATE_H
